/**
 * Program implementation.
 */

#include "Program.h"

/////////////////////////////////////////////////

Program::Program(const std::string& n, ShaderPtr v, ShaderPtr f) : _name(n), _vert(v), _frag(f)
{
	init();
}

/////////////////////////////////////////////////

Program::Program(const std::string& n, const std::string& vPath, const std::string& fPath) 
	: _name(n), 
	_vert(new Shader(vPath, GL_VERTEX_SHADER)), 
	_frag(new Shader(fPath, GL_FRAGMENT_SHADER))
{
	init();
}

/////////////////////////////////////////////////

void Program::init() {
	_glName = glCreateProgram();
	if (_vert) {
		glAttachShader(_glName, _vert->getGLName());
	}
	if (_frag) {
		glAttachShader(_glName, _frag->getGLName());
	}

	glLinkProgram(_glName);
	checkGLError();
}

/////////////////////////////////////////////////

void Program::setFloat(const std::string& name, GLfloat s)
{
	// TODO error check
	GLuint loc = glGetUniformLocation(_glName, name.c_str());
	glUniform1f(loc, s);
}

/////////////////////////////////////////////////

void Program::setInt(const std::string& name, GLint s)
{
	// TODO error check
	GLuint loc = glGetUniformLocation(_glName, name.c_str());
	glUniform1i(loc, s);
}
/////////////////////////////////////////////////

void Program::setSampler(const std::string& name, GLuint s)
{
	// TODO error check
	GLuint loc = glGetUniformLocation(_glName, name.c_str());
	glUniform1i(loc, s);
}

/////////////////////////////////////////////////

void Program::setMatrix(const std::string& name, const Matrix& mat)
{
	GLuint loc = glGetUniformLocation(_glName, name.c_str());
	glUniformMatrix4fv(loc, 1, true, mat.ptr());
}

/////////////////////////////////////////////////

void Program::setVec2(const std::string& name, const Vec2f& v)
{
	GLuint loc = glGetUniformLocation(_glName, name.c_str());
	glUniform2f(loc, v[0], v[1]);
}

/////////////////////////////////////////////////

void Program::setVec2Array(const std::string& name, GLuint num, Vec2f* v)
{
	GLuint loc = glGetUniformLocation(_glName, name.c_str());
	GLfloat* data = new GLfloat[num*2];
	for (GLuint i=0; i<num; i++) {
		data[2*i] = v[i][0];
		data[2*i+1] = v[i][1];
	}
		
	glUniform2fv(loc, num, data);
}

